package com.block.channel.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.channel.enums.ChargeTypeEnum;
import com.block.channel.service.ICountInfoService;
import com.block.channel.service.ICountUvInfoService;
import com.block.channelext.enums.ActionTypeEnum;
import com.block.channelext.service.IActionInfoService;
import com.block.common.annotate.ExceptionLog;
import com.block.common.bean.CommonParam;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.constant.RedisKeyConstant;
import com.block.common.model.dto.CountInfoDTO;
import com.block.common.model.dto.UserInfoDTO;
import com.block.common.enums.CountTypeEnum;
import com.block.common.service.IChannelCommonService;
import com.block.common.service.ICountCommonService;
import com.block.common.service.IProductCommonService;
import com.block.common.service.LogFactory;
import com.block.common.util.LocalDateUtil;
import com.block.common.vo.ResponseVo;
import com.block.db.entity.ChannelInfo;
import com.block.db.entity.CountInfo;
import com.block.db.mapper.CountInfoMapper;
import com.block.product.service.IProductProfitService;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 
 * @since 2022-08-09
 */
@Service
public class CountInfoServiceImpl extends ServiceImpl<CountInfoMapper, CountInfo> implements ICountInfoService {

    private static Logger log = LogFactory.getCommLog();

    @Autowired
    IProductCommonService productCommonService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    ICountCommonService countCommonService;
    @Autowired
    IProductProfitService productProfitService;
    @Autowired
    ICountUvInfoService countUvInfoService;
    @Autowired
    IActionInfoService actionInfoService;
    @Autowired
    IChannelCommonService channelCommonService;

    @Async
    @Override
    public void calculateDataInfo(CountInfoDTO countInfoDTO){
        try {
            countCommonService.calculateDataInfo2(countInfoDTO);
        }catch (Exception exception){
//            异常报警
        }
    }

    /**
     * 处理通过统计接口传进来的数据
     * @param operType
     * @param dataId
     * @param userInfoDTO
     * @return
     */
    @Override
    @ExceptionLog(key = "#operType", bizName = "事件统计", bizType = "SYS_COUNT")
    public ResponseVo handleOperData(String operType, String dataId, UserInfoDTO userInfoDTO, String dataInfo, String dataExt, CommonParam commonParam) {

        String countChannelCode = userInfoDTO.getReqChannelCode();
        if (Arrays.asList("ios_card", "android_card").contains(userInfoDTO.getReqChannelCode())){
            countChannelCode = userInfoDTO.getChannelCode();
        }

        // 数据计算到 用户注册的渠道信息下面（看数据会不会产生什么问题）
        CountInfoDTO countInfoDTO = new CountInfoDTO(countChannelCode);
        if (StrUtil.equals(operType, CountTypeEnum.DOWNLOAD.getValue())){

            // TODO: 2022/11/18 统计产品pv数据
            Long remainSecond = LocalDateUtil.getRemainSecondNumber();
            String redisKey = StrUtil.format(RedisKeyConstant.COUNT_DOWNLOAD_KEY, countChannelCode, userInfoDTO.getIp());
            boolean result = stringRedisTemplate.opsForValue()
                    .setIfAbsent(redisKey, System.currentTimeMillis()+"",remainSecond, TimeUnit.SECONDS);
            if (!result){
                // 加锁不成功，则直接返回
                return new ResponseVo(AppRspCodeConstant.SUCCESS);
            }

            countInfoDTO.setDownloadCount(1);
        }else if (StrUtil.equals(operType, CountTypeEnum.PROD_UV.getValue())){

            // TODO: 2022/11/18 统计产品pv数据
            Long remainSecond = LocalDateUtil.getRemainSecondNumber();
            String redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_PROD_KEY, userInfoDTO.getIp(), dataId);
            boolean result = stringRedisTemplate.opsForValue()
                    .setIfAbsent(redisKey, System.currentTimeMillis()+"",remainSecond, TimeUnit.SECONDS);
            if (!result){
                // 加锁不成功，则直接返回
                return new ResponseVo(AppRspCodeConstant.SUCCESS);
            }
            // 加锁统计成功

            actionInfoService.actionHandle(commonParam.getChannelCode(), ActionTypeEnum.PRO_UV, commonParam, userInfoDTO.getUid());

            // todo 待定 产品收益统计
            BigDecimal profit = productCommonService.getProductProfit(dataId);
            countInfoDTO.setProUvProfit(profit);
            countInfoDTO.setProUvCount(1);

            // 产品收益统计
            // 产品uv统计（去重）
            String sceneId = dataExt;
            productProfitService.saveProductUvProfit(Long.valueOf(dataId), userInfoDTO, sceneId);

        }else if (StrUtil.equals(operType, CountTypeEnum.REQUEST_WECHAT.getValue())){
            String redisKey = StrUtil.format(RedisKeyConstant.COUNT_UV_WECHAT_KEY, userInfoDTO.getChannelCode(), userInfoDTO.getIp());
            boolean result = stringRedisTemplate.opsForValue().setIfAbsent(redisKey, "0", 1L, TimeUnit.DAYS);
            if (!result){
                return new ResponseVo(AppRspCodeConstant.SUCCESS);
            }
            // 3.统计渠道uv信息
            countInfoDTO.setRequestWechatCount(1);

        }else if (StrUtil.equals(operType, CountTypeEnum.CLIENT_DATA_RECORD.getValue())){

            // todo 缓解数据库压力，后期需要储存什么内容再确定
//            countUvInfoService.updateUvCountInfo(dataId, dataInfo, dataExt);
            return new ResponseVo(AppRspCodeConstant.SUCCESS);
        }else {
            return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION);
        }

        countCommonService.calculateDataInfo2(countInfoDTO);
        return new ResponseVo(AppRspCodeConstant.SUCCESS);
    }

    /**
     * 统计uv数据信息
     *
     * @param channelCode
     */
    @Async
    @Override
    public void countUvDataInfo(String channelCode, String reqIp, String userAgent, String uuidStr) {
        CountInfoDTO countInfoDTO = new CountInfoDTO();
        countInfoDTO.setChannelCode(channelCode);
        countInfoDTO.setUvCount(1);

        // 根据渠道号查询渠道信息
        ChannelInfo channelInfo = channelCommonService.getChannelInfoCache(channelCode);
        if (ObjectUtil.equal(channelInfo.getChargeType(), ChargeTypeEnum.UV.getValue())){
            // 非联登渠道，才进行uv 金额的统计
            // 联登渠道，不进行该渠道信息的统计
            countInfoDTO.setUvCost(channelInfo.getChargeAmount());
        }else{
            countInfoDTO.setUvCost(BigDecimal.ZERO);
        }

        try {

            UserAgent userAgentObject = UserAgentUtil.parse(userAgent);
            String browserName = userAgentObject.getBrowser().getName();

            if (StrUtil.equals(browserName, "MicroMessenger")){
                countInfoDTO.setRequestWechatCount(1);
            }

            if (StrUtil.equals(browserName, "QQBrowser")){
                countInfoDTO.setRequestQqCount(1);
            }

        }catch (Exception exception){

        }


        //渠道信息统计
        countCommonService.calculateDataInfo2(countInfoDTO);

        // 每个有效uv的具体信息
        countUvInfoService.saveUvCountInfo(channelCode, reqIp, userAgent, uuidStr);
    }

    /**
     * 统计登陆注册信息
     * @param channelCode
     * @param isNewMember
     */
    @Async
    @Override
    public void countLoginAndRegisterDataInfo(String channelCode, boolean isNewMember, Integer memberType, boolean loginFlag) {
        // 根据渠道号查询渠道信息
        CountInfoDTO countInfoDTO = new CountInfoDTO(channelCode);
        if (isNewMember){
            countInfoDTO.setRegisterCount(1);
            // 判断是否为真实注册量
            if (ObjectUtil.equal(memberType, Integer.valueOf(0))){
                countInfoDTO.setRegisterCountReal(1);
            }else{
                countInfoDTO.setRegisterCountReal(0);
            }
            ChannelInfo channelInfo = channelCommonService.getChannelInfoCache(channelCode);
            BigDecimal regCost = BigDecimal.ZERO;
            if (ObjectUtil.equal(channelInfo.getChargeType(), ChargeTypeEnum.REG.getValue()) ||
                    ObjectUtil.equal(channelInfo.getChargeType(), ChargeTypeEnum.LIANDENG.getValue())){
                 // register 计价
                regCost = channelInfo.getChargeAmount();
            }
            countInfoDTO.setRegisterCost(regCost);
        }
        if (loginFlag){
            countInfoDTO.setLoginCount(1);
        }
        countCommonService.calculateDataInfo2(countInfoDTO);
    }
}
